package edu.umn.csci5511.facedetection;

import java.awt.Color;
import java.awt.Rectangle;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.util.Vector;

import javax.imageio.ImageIO;

import edu.umn.csci5511.facedetection.colorspace.ColorYCbCr;
import edu.umn.csci5511.facedetection.colorspace.ColorYCbCr1;
import edu.umn.csci5511.facedetection.utilities.ImageUtils;

public class FaceDetection {

	/**
	 * @param args
	 */

	public static void main(String[] args) {
		BufferedImage img = null;

		long totalTime = System.currentTimeMillis();
		long startTime = 0;
		try {
			img = ImageIO.read(new File(args[0]));
			ColorModel colorModel = img.getColorModel();
			ColorSpace colorSpace = colorModel.getColorSpace();
			ColorYCbCr[][] imageYCbCr = new ColorYCbCr[img.getHeight()][img.getWidth()];
			ColorYCbCr1[][] imageYCbCr1 = new ColorYCbCr1[img.getHeight()][img.getWidth()];
			boolean skin[][] = new boolean[img.getHeight()][img.getWidth()];
			System.out.println("------0.Time taken for "
					+ (System.currentTimeMillis() - startTime));
			startTime = System.currentTimeMillis();
			int w = img.getRaster().getWidth()*img.getRaster().getHeight()*img.getRaster().getNumDataElements();
			byte arr[] = new byte[w];
//			switch(img.getRaster().getTransferType()) {
//				case DataBuffer.TYPE_BYTE:
//					array = new byte[w];
//					break;
//				case DataBuffer.TYPE_DOUBLE:
//					array = new double[w];
//					break;
//				case DataBuffer.TYPE_FLOAT:
//					array = new float[w];
//					break;
//				case DataBuffer.TYPE_INT:
//					array = new int[w];
//					break;
//				case DataBuffer.TYPE_SHORT:
//					array = new short[w];
//					break;
//			}
			arr = (byte[])img.getRaster().getDataElements(img.getMinX(), img.getMinY(), img.getWidth(), img.getHeight(), arr);
			System.out.println("------0.Time taken for loading all"
					+ (System.currentTimeMillis() - startTime));
			if (colorSpace.getType() == ColorSpace.TYPE_YCbCr) {
				System.out.println("Converting from YCbCr to YCb'Cr'");
				for (int i = img.getMinX(); i < img.getWidth(); i++) {
					startTime = System.currentTimeMillis();
					for (int j = img.getMinY(); j < img.getHeight(); j++) {
						System.out.println("------1.Time taken for stage " + i
								+ " "
								+ (System.currentTimeMillis() - startTime));
						imageYCbCr[i][j] = new ColorYCbCr(arr[i*img.getWidth() + j*img.getHeight() + 0], arr[i*img.getWidth() + j*img.getHeight() + 0],
								arr[i*img.getWidth() + j*img.getHeight() + 0]);
						System.out.println("------2.Time taken for stage " + i
								+ " "
								+ (System.currentTimeMillis() - startTime));
						imageYCbCr1[i][j] = ImageUtils
								.fromYCbCrToYCbCr1(imageYCbCr[i][j]);
						System.out.println("------2.Time taken for stage " + i
								+ " "
								+ (System.currentTimeMillis() - startTime));
					}
				}
			} else if (colorSpace.getType() == ColorSpace.TYPE_RGB) {
				
				int size = 0;
				System.out.println("Converting from RGB to YCb'Cr'");
				//TODO: If nothing works to speed up, we can parallelize these operations in threads
				// like for a batch of X pixels we can have a thread operating on the y pixels.
				long startTime1 = System.currentTimeMillis();
				for (int i = img.getMinY(); i < img.getHeight(); i++) {
					startTime = System.currentTimeMillis();
					for (int j = img.getMinX(); j < img.getWidth(); j++) {
						// j=1(0)->img.getWidth();
//						System.out.println("1------1.Time taken for stage " + i
//								+ " "
//								+ (System.currentTimeMillis() - startTime));
//						int arr[] = img.getData().getPixel(i, j, new int[3]);
//						img.getRGB(i, j);
//						System.out.println("1------2.Time taken for stage " + i
//								+ " "i
//								+ (System.currentTimeMillis() - startTime));
//						imageYCbCr[i][j] = ImageUtils.fromRGBtoYCbCr(arr[i + j*img.getHeight() + 0], arr[i + j*img.getHeight()  + 1],
//								arr[i + j*img.getHeight() + 2]);
						size = 	(i*img.getWidth() + j)*3 + 2;
						short r = (short)(arr[(i*img.getWidth() + j)*3 + 0] + 128);
						short g = (short)(arr[(i*img.getWidth() + j)*3 + 1] + 128);
						short b = (short)(arr[(i*img.getWidth() + j)*3 + 2] + 128);
						if(r<0 || g<0 || b<0 || r>255 || g>255 || b>255) {
							System.out.println("R:" + r + " G:" + g + " B:" + b);
							int ar[] = img.getData().getPixel(j, i, new int[3]);
							System.out.println("R:" + ar[0] + " G:" + ar[1] + " B:" + ar[2]);
						}
						imageYCbCr[i][j] = ImageUtils.fromRGBtoYCbCr(r, g, b);
//						System.out.println("1------3.Time taken for stage " + i
//								+ " "
//								+ (System.currentTimeMillis() - startTime));
						imageYCbCr1[i][j] = ImageUtils.fromYCbCrToYCbCr1(imageYCbCr[i][j]);
						skin[i][j] = ImageUtils.isSkinColor(imageYCbCr1[i][j]);
						if(skin[i][j]) {
							img.setRGB(j, i, Color.black.hashCode());
						}
					}
					System.out.println("1------4.Time taken for stage " + i
							+ " "
							+ (System.currentTimeMillis() - startTime));
				}
				
				System.out.println("1------4.Totatl Time Taken " + (System.currentTimeMillis() - startTime1));
				System.out.println("raster w: " + img.getRaster().getWidth() + " img width: " + img.getWidth());
				System.out.println("raster w: " + img.getRaster().getHeight() + " img width: " + img.getHeight());
				System.out.println("Size: " + size + " w : " + w + "Number DataElement: " + img.getRaster().getNumDataElements() + " arrsize: " + arr.length);
			} else {
				// TODO add other colorschemes
				System.out.println("Other");
			}
			ImageIO.write(img, "jpg", new File("D:\\test.jpg"));
			System.out.println("Done Conversion to YCb'Cr'");
		} catch (IOException e) {
			e.printStackTrace();
		} finally{
			System.out.println("Total time elapsed:" + (System.currentTimeMillis()-totalTime));
			
		}
		System.out.println("Terminated!");
	}

}
